<template>
  <div class="search-and-table-container">
    <!-- 查询表单 -->
    <iSearch
      :infos="searchData"
      submitText="查询"
      :submit-hide="!searchData.length"
      operateType="search"
      submitPosition="top"
      :submitVoid="submitVoid"
      @submit="_query"
      @on-enter="_query"
      @on-clear="_query"
    ></iSearch>
    <!-- 可插入功能按钮 -->
    <slot name="operate" :list="operateData">
      <div v-if="operateData.length" style="margin-bottom: 20px">
        <template v-for="(o, i) in operateData">
          <Button
            @click="() => o.click(o, i)"
            :type="o.type || `primary`"
            :size="o.size || `default`"
            style="margin-right: 15px"
            :style="o.style"
            :key="i"
          >{{o.label}}</Button>
        </template>
      </div>
    </slot>
    <!-- 表体 -->
    <slot :list="tableData" :loading="loading">
      <iTable
        ref="table"
        :border="border"
        :loading="loading"
        :columns="tableColumns"
        :table-data="tableData"
        :row-class-name="rowClassName"
        :highlight-row="highlightRow"
        :row-key="rowKey"
        @on-sort-change="_sortChange"
        @on-select="_select"
        @on-select-all="_selectAll"
        @on-selection-change="_selectChange"
        @on-row-click="_rowClick"
        @on-row-dblclick="_rowDbclick"
      ></iTable>
    </slot>
    <Page
      :total="total"
      show-sizer
      @on-change="pageChange"
      :current.sync="tableDefaultParam.page"
      @on-page-size-change="pageSizeChange"
      :page-size="tableParam.size"
      :page-size-opts="pageSizeOpts"
      :show-elevator="showElevator"
      class="table-page"
    />
  </div>
</template>

<script>
import iTable from './table'
import iSearch from './../EditForm/index'
import tooltip from './tools/tooltip'
import { columns, getTableData, searchData } from './mock'
import { Page } from 'view-design'
export default {
  name: 'SearchAndTable',
  // 对外抛出的column属性，用于render组件
  tooltip,
  components: {
    iTable,
    iSearch,
    Page
  },
  props: {
    columns: {
      type: Array,
      default: () => columns
    },
    // 表格的过滤条件展示
    searchData: {
      type: Array,
      default: () => searchData
    },
    // 表格的操作按钮: [{ label: '新增', click: () => '新增' }]
    operateData: {
      type: Array,
      default: Array
    },
    // 表格接口: Function
    getTableData: {
      type: Function,
      default: getTableData
    },
    // 额外的参数
    param: {
      type: Object,
      default: Object
    },
    // 表格的参数（仅指当前页和页码）
    tableParam: {
      type: Object,
      default: () => ({
        page: 1,
        size: 10
      })
    },
    // 表格参数key的名称（接口对当前页和页码字段的定义，默认page、size）
    // Object{page,size} | Array[page,size]
    tableParamKey: {
      type: [Object, Array],
      default: () => ({
        pageKey: 'page', // page number pageNo
        sizeKey: 'size' // size number pageSize
      })
    },
    // 是否查询无效内容（当value为空字符串时），默认不提交
    submitVoid: {
      type: Boolean,
      default: false
    },
    border: {
      type: Boolean,
      default: true
    },
    // 确定每一行的类名（每一列的类名在columns中设置className）
    rowClassName: {
      type: Function,
      default: () => {} // (row, index) => ''
    },
    // 是否支持高亮选中的行，即单选
    highlightRow: {
      type: Boolean,
      default: false
    },
    // 是否强制使用内置的 row-key，开启后可能会影响性能
    rowKey: {
      type: [Boolean, String],
      default: false
    },
    pageSizeOpts: {
      type: Array,
      default: function () {
        let num = this.tableParam.size
        return [ num, 2 * num, 3 * num ]
      }
    },
    // 分页: 是否显示跳转至某页
    showElevator: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      // 行数据
      tableData: [],
      // 列数据
      tableColumns: [],
      // 接口参数
      searchParam: {},
      sortParam: {},
      tableDefaultParam: this.tableParam,
      total: 0,
      // loading
      loading: true
    }
  },
  computed: {
    /**
     * table的参数：
     * 基础参数：page、size
     * 搜索参数：EditForm.$emit('submit', v):searchParam
     * 排序参数：sortable=custom.$emit('on-sort-change'):sortParam
     * 额外参数：props:param
     */
    _tableParam () {
      let { page, size } = this.tableDefaultParam
      let { pageKey, sizeKey } = this.tableParamKey
      if (Array.isArray(this.tableParamKey)) {
        const [page, size] = this.tableParamKey
        pageKey = page
        sizeKey = size
      }
      let parameters = Object.assign(
        {},
        this.searchParam,
        this.sortParam,
        this.param,
        {
          [pageKey]: page,
          [sizeKey]: size
        }
      )
      return parameters
    }
  },
  watch: {
    param: {
      immediate: true,
      handler () {
        this._initTableData()
      }
    },
    columns: {
      immediate: true,
      handler (v) {
        this.tableColumns = v.map(o => {
          // tooltip
          if (typeof o.tooltip === 'function') {
            o.render = (h, { row }) => {
              let { txt = 'txt内容', content = 'content内容' } = o.tooltip(row) || {}
              return h(tooltip, { // 其他方法见：tooltip
                props: { txt, content }
              })
            }
          // value为回调函数时，可以默认查询并设置显示值
          } else if (typeof o.value === 'function') {
            const callback = o.value
            o.render = (h, { row }) => h('div', callback(row[o.key], row))
          // list存在且为Array时，可以默认查询并设置显示值
          } else if (Array.isArray(o.list)) {
            o.render = (h, { row }) => {
              let item = o.list.find(e => [e.value, e.id].includes(row[o.key]))
              let value = item ? item.label || item.name || item.title : ''
              return h('div', value)
            }
          // list存在且为MAP时，可以默认查询并设置显示值
          } else if (typeof o.list === 'object') {
            o.render = (h, { row }) => {
              let MAP = o.list
              let value = MAP[row[o.key]] || ''
              return h('div', value)
            }
          // $index存在时，可以设置显示值为真实索引（type为index时为当前页面索引）
          } else if (o.type === '$index') {
            o.key = '_$index'
          }
          return o
        })
      }
    }
  },
  methods: {
    /**
     * 初始化表格数据：
     * 大量数据渲染时：处理loading问题
     * 筛选onClear时：处理顺序问题
     * 外部调用该方法，请用 search 或者 refresh
     */
    async _initTableData () {
      // on-clear数据变化顺序不对
      await this.$nextTick(() => {})
      // 获取数据时开启遮罩，并抛出一个更新状态
      this.loading = true
      this.$emit('loading', true)
      this.$emit('table-param', this._tableParam)
      console.log(this._tableParam)
      const result = await this.getTableData(this._tableParam)
      let { total, data } = result
      this.loading = false
      this.$emit('loading', false)
      // 数据获取结束，更新table数据
      this.total = total
      this.tableData = data
      if (this.tableColumns.some(o => o.key === '_$index')) {
        let { page, size } = this.tableDefaultParam
        let num = (page - 1) * size
        data.map((o, i) => {
          o._$index = num + i + 1
        })
      }
      this.$emit('interface-data', result)
      this.$emit('table-data', data)
    },
    search () {
      this._initTableData()
    },
    refresh () {
      this._initTableData()
    },
    /**
     * 筛选栏部分
     * 1、搜索
     * 2、重置
     */
    _query (v) {
      this.searchParam = v
      this.tableDefaultParam.page = 1
      this._initTableData()
    },
    /**
     * 功能方法部分
     *
     * 1、导出：
     * exportCsv 将数据导出为 .csv 文件，参数说明params(Object):
     * filename 文件名，默认为 table.csv
     * original 是否导出为原始数据，默认为 true
     * noHeader 不显示表头，默认为 false
     * columns 自定义导出的列数据
     * data 自定义导出的行数据
     * callback 添加此函数后，不会下载，而是返回数据
     * separator 数据分隔符，默认是逗号(,)
     * quoted 每项数据是否加引号，默认为 false
     * 说明：columns 和 data 需同时声明，声明后将导出指定的数据，建议列数据有自定义render时，可以根据需求自定义导出内容
     *
     */
    export (params) {
      this.exportCsv(params)
    },
    exportCsv (params = {}) {
      this.$refs.table.exportCsv(params)
    },
    /**
     * 表格多选模式
     *
     * 1、on-select（单选）
     * 选中某项时触发，抛出选中项和当前选中项
     *
     * 2、on-select-all（多选）
     * 全选时触发，抛出选中项
     *
     * 3、on-selection-change
     * 选项变化时触发，抛出选中项
     *
     */
    _select (selection, row) {
      this.$emit('on-select', selection, row)
    },
    _selectAll (selection) {
      this.$emit('on-select-all', selection)
    },
    selectAll (isChecked = true) {
      this.$refs.table.selectAll(isChecked)
    },
    _selectChange (selection) {
      this.$emit('on-selection-change', selection)
    },
    /**
     * 表格点击行事件
     *
     * 1、on-row-click（单击）
     * 单击某一行是触发，抛出当前行和索引
     *
     * 2、on-row-dbclick（双击）
     * 双击某一行是触发，抛出当前行和索引
     *
     */
    _rowClick (row, index) {
      this.$emit('on-row-click', row, index)
    },
    _rowDbclick (row, index) {
      this.$emit('on-row-dbclick', row, index)
    },
    /**
     * 排序模式
     */
    _sortChange ({key, sortable}) {
      this.sortParam = {key, sortable}
      this._initTableData()
    },
    /**
     * 表格展开部分
     */
    /**
     * 分页组件部分
     *
     */
    pageChange (v) {
      this.$emit('page-change', v)
      this.tableDefaultParam.page = v
      this._initTableData()
    },
    pageSizeChange (v) {
      this.tableDefaultParam.size = v
      this._initTableData()
    }
  }
}
</script>

<style scoped>
/* 完全包含.table-page的margin */
.search-and-table-container {
  overflow: hidden;
}
.table-page {
  margin: 15px 0;
}
</style>
